/**
 * Mise en oeuvre de Echiquier.h
 *
 * @file Echiquier.cxx
 */

#include <iostream>
#include <cstdlib>

// A besoin de la declaration de la classe
#include "Echiquier.h"
#include "Piece.h"
#include "Pion.h"
#include "Tour.h"
#include "Cavalier.h"
#include "Roi.h"
#include "Reine.h"
#include "Fou.h"

using namespace std;

/**
 * Constructeur par défaut.
 * Initialise à vide l'echiquier.
 */
Echiquier::Echiquier()
{
}

/**
 * Recupere la piece situee sur une case.
 *
 * @param x un entier entre 1 et 8
 * @param y un entier entre 1 et 8
 *
 * @return 0 si aucune piece n'est sur cette case et un pointeur
 * vers une piece sinon.
 */
PiecePtr Echiquier::getPiece(int x, int y) const
{
	return m_cases[(y - 1) * 8 + (x - 1)];
}


/**
 * Place une piece sur l'echiquier, aux coordonnees specifiees dans la piece.
 *
 * @param p un pointeur vers une piece
 *
 * @return 'true' si le placement s'est bien passe, 'false' sinon
 * (case occupee, coordonnees invalides, piece vide )
 */
bool Echiquier::placer(PiecePtr p)
{
	// Piece vide
	if (p == NULL)
		return false;

	int x = p->x();
	int y = p->y();

	// Coordonnees invalides
	if (x < 1 || x > 8 || y < 1 || y > 8)
		return false;

	// Case deja occupee
	if (this->getPiece(x, y) != NULL)
		return false;

	// Tous les tests sont passes, on place la piece
	m_cases[(y - 1) * 8 + (x - 1)] = p;
	return true;
}


/**
 * Deplace une piece sur l'echiquier, des coordonnees specifiees
 * dans la piece aux coordonnees x,y.
 *
 * @param p un pointeur vers une piece
 * @param x un entier entre 1 et 8
 * @param y un entier entre 1 et 8
 *
 * @return 'true' si le placement s'est bien passe, 'false' sinon
 * (case occupee, coordonnees invalides, piece vide, piece pas
 * presente au bon endroit sur l'echiquier)
 */
bool Echiquier::deplacer(PiecePtr p, int x, int y)
{
	// Piece vide
	if (p == NULL)
		return false;

	// Coordonnees invalides
	if (x < 1 || x > 8 || y < 1 || y > 8)
		return NULL;

	// Case occupee
	if (this->getPiece(x, y) != NULL)
		return false;

	int px = p->x();
	int py = p->y();

	// Piece pas au bon endroit
	if (px < 1 || px > 8 || py < 1 || py > 8)
		return NULL;

	// Depart et arrivee identiques
	if (x == px && y == py)
		return false;

	// Tous les tests sont passes, on peut bouger la piece
	p->move(x, y);
	return this->placer(p);
}


/**
 * Enleve la piece situee sur une case (qui devient vide).
 *
 * @param x un entier entre 1 et 8
 * @param y un entier entre 1 et 8
 *
 * @return 0 si aucune piece n'est sur cette case et le pointeur
 * vers la piece enlevee sinon.
 */
PiecePtr Echiquier::enleverPiece(int x, int y)
{
	// Coordonnees invalides
	if (x < 1 || x > 8 || y < 1 || y > 8)
		return PiecePtr();

	// Case inoccupee
	if (this->getPiece(x, y) == NULL)
		return PiecePtr();

	// Ok
	PiecePtr p = this->getPiece(x, y);
	m_cases[(y - 1) * 8 + (x - 1)].reset();
	return p;
}


/**
 * Affiche l'echiquier avec des # pour les cases noires et . pour
 * les blanches si elles sont vides, et avec B pour les pieces
 * blanches et N pour les pieces noires.
 */
void Echiquier::affiche() const
{
	cout << endl << "  12345678" << endl;

	for (int y = 1; y <= 8; ++y)
	{
		cout << y << " ";

		for (int x = 1; x <= 8; ++x)
		{
			char c;
			PiecePtr p = this->getPiece(x, y);

			if (p == 0)
				c = ((x + y) % 2) == 0 ? '#' : '.';

			else
			{
				if (tr1::dynamic_pointer_cast<Pion>(p) != NULL)
					c = p->isWhite() ? 'P' : 'p';

				if (tr1::dynamic_pointer_cast<Tour>(p) != NULL)
					c = p->isWhite() ? 'T' : 't';

				if (tr1::dynamic_pointer_cast<Cavalier>(p) != NULL)
					c = p->isWhite() ? 'C' : 'c';

				if (tr1::dynamic_pointer_cast<Fou>(p) != NULL)
					c = p->isWhite() ? 'F' : 'f';

				if (tr1::dynamic_pointer_cast<Roi>(p) != NULL)
					c = p->isWhite() ? 'R' : 'r';

				if (tr1::dynamic_pointer_cast<Reine>(p) != NULL)
					c = p->isWhite() ? 'Q' : 'q';
			}

			cout << c;
		}

		cout << " " << y << endl;
	}

	cout << "  12345678" << endl;
}
